package com.yfyszk.kingbird.aspect;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.yfyszk.kingbird.annotation.Log;
import com.yfyszk.kingbird.common.utils.JWTUtils;
import com.yfyszk.kingbird.entity.SystemLog;
import com.yfyszk.kingbird.service.queue.SystemLogQueue;
import com.yfyszk.kingbird.util.IpUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 记录日志切面
 *
 * @author wgc
 * @since on 2018/5/10.
 */
@Slf4j
public class RecordLogAspect extends AbstractAspectManager {
    public HashMap<String, Object> resultMap = new HashMap<String, Object>();
    public static final String SESSION_USER = "currentUser";
    private static final Cache<String, Object> CACHES = CacheBuilder.newBuilder()
            // 最大缓存 100 个
            .maximumSize(1000)
            // 设置写缓存后 60 秒过期
            .expireAfterWrite(60, TimeUnit.SECONDS)
            .build();

    public RecordLogAspect(AspectApi aspectApi) {
        super(aspectApi);
    }

    @Override
    public Object doHandlerAspect(ProceedingJoinPoint pjp, Method method) throws Throwable {
        super.doHandlerAspect(pjp, method);
        return execute(pjp, method);
    }

    private Logger logger = LoggerFactory.getLogger(RecordLogAspect.class);

    @Override
    @Async
    protected Object execute(ProceedingJoinPoint pjp, Method method) throws Throwable {
        Log log = method.getAnnotation(Log.class);
        // 异常日志信息
        String actionLog = null;
        StackTraceElement[] stackTrace = null;
        // 是否执行异常
        boolean isException = false;
        // 接收时间戳
        long endTime;
        // 开始时间戳
        long operationTime = System.currentTimeMillis();
        try {
            return pjp.proceed(pjp.getArgs());
        } catch (Throwable throwable) {
            isException = true;
            actionLog = throwable.getMessage();
            stackTrace = throwable.getStackTrace();
            throw throwable;
        } finally {
            //防止表单重复提交
           /* FormLock formLock = method.getAnnotation(FormLock.class);
            if (formLock != null) {
                RequestAttributes ra = RequestContextHolder.getRequestAttributes();
                ServletRequestAttributes sra = (ServletRequestAttributes) ra;
                HttpServletRequest request = sra.getRequest();
                String authorization = request.getHeader("token");
                String key = getKey(request, method, authorization);
                logger.info("key:{}", key);
                if (!StringUtils.isEmpty(key)) {
                    if (CACHES.getIfPresent(key) != null) {
                        throw new GlobalServiceException(1, "请勿重复提交");
                    }
                    // 如果是第一次请求,就将 key 当前对象压入缓存中
                    CACHES.put(key, key);
                }
            }*/
            // 日志处理
            logHandle(pjp, method, log, actionLog, operationTime, isException, stackTrace);
        }
    }

    private void logHandle(ProceedingJoinPoint joinPoint,
                           Method method,
                           Log logs,
                           String actionLog,
                           long startTime,
                           boolean isException,
                           StackTraceElement[] stackTrace) {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        //test
        String token = JWTUtils.createSign(String.valueOf("123"), "1234565", 200l);
        String userId = JWTUtils.getUserId(token);
        String authorization = request.getHeader("token");
        log.info("authorization:{}",authorization);
        SystemLog sysLog = new SystemLog();
        String unitId=null;
        /*if (!ComUtils.isEmpty(authorization)) {
            String userId = JWTUtils.getUserId(authorization);
            if(StringUtils.isNotBlank(userId)){
                sysLog.setUserId(Long.parseLong(userId));
            }
            //保存登陆者的单位
            unitId= JWTUtils.getUnitId(authorization);
            if(StringUtils.isNotBlank(unitId)){
                sysLog.setUnitId(Long.parseLong(unitId));
            }

        }*/

        /*if(StringUtils.isBlank(unitId)){
            UserVO user = (UserVO) request.getSession().getAttribute("currentUser");
            logger.info("用户信息:{}",user);
            if(user!=null){
                sysLog.setUnitId(user.getCompanyId());
                sysLog.setUserId(user.getId());
            }

        }*/
        Log syslog = method.getAnnotation(Log.class);
        String methodDescp = syslog.description();
        logger.info("方法描述:{}", methodDescp);
        String methodModelName = syslog.modelName();
        logger.info("模块名称:{}", methodModelName);
        String methodaction = syslog.action();
        logger.info("操作方法:{}", methodaction);
        if (isException) {
            StringBuilder sb = new StringBuilder();
            sb.append(actionLog + "#10;");
            for (int i = 0; i < stackTrace.length; i++) {
                sb.append(stackTrace[i] + "#10;");
            }
            String json = JSONUtil.formatJsonStr(sb.toString());
            logger.info("异常信息:{}", json);
            sysLog.setOptContent(json);
        }

        long endTime = System.currentTimeMillis();
        //logger.info("doAround>>>耗时：{}", endTime - startTime + "毫秒");
        sysLog.setCreateTime(new Date());
        //操作方法
        sysLog.setMethodName(methodaction);
        //方法名描述
        sysLog.setMethodDesr(methodDescp);
        //操作状态
        sysLog.setStatus(syslog.status());
        //操作终端类型
        sysLog.setPlatformType(syslog.platform());
        //操作类型
        log.info("远程IP:{}",request.getRemoteAddr());
        //log.info("本地IP:{}",ServletUtils.getLocalIP());
         sysLog.setUserIp(request.getRemoteAddr());
        sysLog.setUrl(request.getRequestURI());
        sysLog.setMethod(request.getMethod());
        sysLog.setCreateTime(new Date());
        sysLog.setUserAgent(request.getHeader("User-Agent"));
        sysLog.setSpeedTime((int) (endTime - startTime));
        Object[] args = joinPoint.getArgs();
        StringBuilder sb = new StringBuilder();
        boolean isJoint = false;
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof JSONObject) {
                JSONObject parse = (JSONObject) JSONObject.parse(args[i].toString());
                //operationLog.setActionArgs(parse.toString());
            } else if (args[i] instanceof String
                    || args[i] instanceof Long
                    || args[i] instanceof Integer
                    || args[i] instanceof Double
                    || args[i] instanceof Float
                    || args[i] instanceof Byte
                    || args[i] instanceof Short
                    || args[i] instanceof Character) {
                isJoint = true;
            } else if (args[i] instanceof String[]
                    || args[i] instanceof Long[]
                    || args[i] instanceof Integer[]
                    || args[i] instanceof Double[]
                    || args[i] instanceof Float[]
                    || args[i] instanceof Byte[]
                    || args[i] instanceof Short[]
                    || args[i] instanceof Character[]) {
                Object[] strs = (Object[]) args[i];
                StringBuilder sbArray = new StringBuilder();
                sbArray.append("[");
                for (Object str : strs) {
                    sbArray.append(str.toString() + ",");
                }
                sbArray.deleteCharAt(sbArray.length() - 1);
                sbArray.append("]");
                logger.info("请求参数:[{}]", sbArray.toString());
            } else {
                continue;
            }
        }
        if (isJoint) {
            Map<String, String[]> parameterMap = request.getParameterMap();
            for (String key : parameterMap.keySet()) {
                String[] strings = parameterMap.get(key);
                for (String str : strings) {
                    sb.append(key + "=" + str + "&");
                }
            }
            logger.info("请求参数:[{}]", sb.toString());
        }
        /*taskExecutor.execute(() -> {
            operationLogService.insert(sysLog);
        });*/
        SystemLogQueue.getInstance().push(sysLog);
    }


    /**
     * 获取getKey
     *
     * @param request
     * @param method
     * @return
     */
    private String getKey(HttpServletRequest request, Method method, String userId) {
        StringBuffer sb = new StringBuffer();
        String requestURI = request.getRequestURI();
        // 拼接请求路径
        sb.append(requestURI);
        // 拼接目标方法名称
        sb.append(method.getName());
        sb.append(userId);
        Map<String, String[]> parameterMap = request.getParameterMap();
        if (parameterMap != null) {
            Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
            if (entries != null) {
                for (Map.Entry<String, String[]> entry : entries) {
                    sb.append(entry.getKey()).append(Arrays.toString(entry.getValue()));
                }
            }
        }
        return sb.toString();
    }
}
